package com.wanmait.schedule.shiro;

import com.wanmait.schedule.entity.Permission;
import com.wanmait.schedule.entity.Role;
import com.wanmait.schedule.entity.Teacher;
import com.wanmait.schedule.service.RoleService;
import com.wanmait.schedule.service.TeacherService;
import com.wanmait.schedule.util.JWTUtils;
import com.wanmait.schedule.util.RedisUtil;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

//@Component
public class ShiroRealm extends AuthorizingRealm {

    @Resource
    private TeacherService teacherService;
    @Resource
    private RoleService roleService;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private RedisUtil redisUtil;

    //执行授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("doGetAuthorizationInfo................");
        //同SimpleAuthenticationInfo的第一个参数
        Teacher teacher = (Teacher)principalCollection.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //角色集合
        List<Role> roleList = teacherService.findRoles(teacher.getId());
      /*  Set<String> roleSet = roleList.stream().map(role -> role.getRole()).collect(Collectors.toSet());
        authorizationInfo.setRoles(roleSet);*/


        //角色id集合
        List<Integer> roleIdList = roleList.stream().map(role -> role.getId()).collect(Collectors.toList());
        //权限集合
        List<Permission> permissions = roleService.findRoles(roleIdList);

        Set<String> permissionSet = permissions.stream().map(permission -> permission.getPerm()).collect(Collectors.toSet());
        authorizationInfo.setStringPermissions(permissionSet);

        return authorizationInfo;
    }

    //执行认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("doGetAuthenticationInfo..................");
        BearerToken bearerToken =(BearerToken) authenticationToken;
        //获得jwt生成的token
        String token = bearerToken.getToken();

        //Integer id = Integer.parseInt(JWTUtils.getAudience(token));
        //String username = JWTUtils.getClaimByName(token,"username");
        Teacher teacher = (Teacher) redisUtil.get("auth:" + token);
//        Teacher teacher =(Teacher) redisTemplate.opsForValue().get("auth:"+token);
        if(teacher==null){
            throw  new AuthenticationException("token过期或者格式错误");
        }
        //验证token是否正确
        JWTUtils.verifyToken(token,teacher.getPassword());

        HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
        request.setAttribute("teacher",teacher);



        //参数1可以是username或者admin对象，参数2为正确的凭证，底层会比较正确的凭证和用户提交的凭证是否一致，参数3为real的名字，唯一即可
        return new SimpleAuthenticationInfo(teacher,token,this.getName());
    }

    //如果不使用UsernameAndPasswordToken需要重写下面的方法
    //org.apache.shiro.authc.pam.UnsupportedTokenException
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof BearerToken;
    }

    //清除缓存
    public void clearCached() {
        /*PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
        super.clearCache(principals);*/
        getAuthorizationCache().clear();
        getAuthenticationCache().clear();
    }

}
